package com.glsc.ngateway.oaflow.service.xirtrade;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import com.glsc.ngateway.common.api.ldap.dto.LdapEhrDeptDto;
import com.glsc.ngateway.common.api.ldap.dto.LdapEhrEmpDto;
import com.glsc.ngateway.common.api.ldap.feign.IFeignLdapService;
import com.glsc.ngateway.common.api.ldap.resp.AppEhrResponse;
import com.glsc.ngateway.common.base.domain.mysql.gateway.oaflow.xirtrade.TOaFlowXirTradeConfigUserRelated;
import com.glsc.ngateway.common.base.domain.mysql.gateway.oaflow.xirtrade.TOaFlowXirTradeInfo;
import com.glsc.ngateway.common.api.oaflow.dto.xirtrade.TOaFlowXirTradeBaseInfoDto;
import com.glsc.ngateway.common.api.oaflow.dto.xirtrade.TOaFlowXirTradeConfigDto;
import com.glsc.ngateway.common.base.repo.mysql.gateway.oaflow.TOaFlowXirTradeConfigUserRelatedRepository;
import com.glsc.ngateway.common.xir.domain.TtrdOtcTrade;
import com.glsc.ngateway.common.xir.domain.VrptAccSecuAll;
import com.glsc.ngateway.common.xir.repo.VrptAccSecuAllRepository;
import com.glsc.ngateway.oaflow.service.xirtrade.enums.XirTradeOaFlowConfigAccountTypeEnum;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import org.apache.logging.log4j.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.lang.Nullable;

import javax.annotation.Resource;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public abstract class AbstractXirTradeFactory {

    static Logger logger = LoggerFactory.getLogger(AbstractXirTradeFactory.class);
    private VrptAccSecuAllRepository vrptAccSecuAllRepo;
    private static IFeignLdapService iFeignLdapService;
    private static TOaFlowXirTradeConfigUserRelatedRepository configUserRelatedRepo;
    private static IFeignLdapService feignLdapService;
    protected ReentrantLock lock = new ReentrantLock();

    @Resource
    public void setConfigUserRelatedRepo(TOaFlowXirTradeConfigUserRelatedRepository configUserRelatedRepo) {
        AbstractXirTradeFactory.configUserRelatedRepo = configUserRelatedRepo;
    }

    @Resource
    public void setiFeignLdapService(IFeignLdapService iFeignLdapService) {
        AbstractXirTradeFactory.iFeignLdapService = iFeignLdapService;
    }

    @Resource
    public void setVrptAccSecuAllRepo(VrptAccSecuAllRepository vrptAccSecuAllRepo) {
        this.vrptAccSecuAllRepo = vrptAccSecuAllRepo;
    }

    @Resource
    public void setFeignLdapService(IFeignLdapService feignLdapService) {
        AbstractXirTradeFactory.feignLdapService = feignLdapService;
    }
    public boolean tryLock(){
        return this.lock.tryLock();
    }
    public void lock(){
        this.lock.lock();
    }

    public void unlock(){
        this.lock.unlock();
    }
    /**
     * 根据日期查询所有已配置的类别，生成未步过的数据
     */
    public abstract <T extends TOaFlowXirTradeBaseInfoDto> List<T> buildUnsyncTradeInfo(@NotNull String date);

    protected <P extends AbstractBuildContext> void initAccid(P context) {
        TOaFlowXirTradeConfigDto config = context.getConfig();
        switch (XirTradeOaFlowConfigAccountTypeEnum.seek(config.getAccountType())) {
            case 资金账户:
                context.setCashAccidList(Strings.isNotBlank(config.getAccount()) ? List.of(config.getAccount().split(",")) : null);
                break;
            case 证券账户:
                context.setSecuAccidList(Strings.isNotBlank(config.getAccount()) ? List.of(config.getAccount().split(",")) : null);
                break;
            case 账户树_证券账户:
                context.setSecuAccidList(Strings.isBlank(config.getAccount()) ? null :
                        Stream.of(config.getAccount().split(","))
                                .map(c -> vrptAccSecuAllRepo.findAllByVcPortNameLike(c))
                                .flatMap(i -> i.stream().map(VrptAccSecuAll::getAccid))
                                .collect(Collectors.toList())
                );
                break;
            default:

        }
    }

    protected static <P extends TOaFlowXirTradeBaseInfoDto, T extends AbstractBuildContext<P>> void setEmpByTraderList(T context) {
        //交易员预查
        List<String> traderList = context.getTradeList().stream().map(TtrdOtcTrade::getTrader).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(traderList)) {
            logger.info("衡泰同步查询人员信息{}", traderList);
            AppEhrResponse<List<LdapEhrEmpDto>> resp = iFeignLdapService.getEmpsByAccounts(traderList);
            logger.info("衡泰同步查询人员信息{}", resp);
            Set<String> oaAccountSet = (Objects.isNull(resp) || !resp.isSuccess() || Objects.isNull(resp.getData())) ? Collections.EMPTY_SET :
                    resp.getData().stream().map(LdapEhrEmpDto::getBadge).collect(Collectors.toSet());
            context.setOaAccountSet(oaAccountSet);
        }
    }

    protected static String getOaUserAccount(TOaFlowXirTradeConfigDto config, TtrdOtcTrade trade, Set<String> oaAccountSet) {
        return Strings.isNotBlank(config.getOaFlowCreator()) ? config.getOaFlowCreator()
                : Optional.ofNullable(configUserRelatedRepo.findByXirUserName(trade.getOperator())).orElseGet(() -> {
                    //未配置衡泰人员关联，直接去oa查找
                    Assert.isTrue(oaAccountSet.contains(trade.getOperator()), "衡泰指令同步异常，未匹配到创建人" + trade.getOperator());
                    TOaFlowXirTradeConfigUserRelated configUserRelate = new TOaFlowXirTradeConfigUserRelated();
                    configUserRelate.setOaUserName(trade.getOperator());
                    return configUserRelate;
                })
                .getOaUserName();
    }

    protected static String getDeptTitle(String account) {
        if (Strings.isBlank(account)) {
            return Strings.EMPTY;
        }
        LdapEhrDeptDto dept = feignLdapService.getDepByAccount(account).getData();
        if (Objects.isNull(dept)) {
            return Strings.EMPTY;
        }
        return dept.getDtitle();
    }

    abstract String getType();

    /**
     * 生产过程上下文
     */
    @SuperBuilder
    @AllArgsConstructor
    @NoArgsConstructor
    @Data
    static class AbstractBuildContext<T extends TOaFlowXirTradeBaseInfoDto> {
        @NotBlank
        private String date;
        @NotNull
        private TOaFlowXirTradeConfigDto config;

        @Builder.Default
        private List<TOaFlowXirTradeInfo> existTradeInfoList = new ArrayList<>(0);
        /**
         * 资金账号
         */
        @Nullable
        private List<String> cashAccidList;
        /**
         * 证券账号
         */
        @Nullable
        private List<String> secuAccidList;
        /**
         * 交易信息列表（主要）
         */
        @Builder.Default
        private List<TtrdOtcTrade> tradeList = new ArrayList<>(0);

        @Builder.Default
        private Set<String> oaAccountSet = new HashSet<>(0);
        /**
         * 生产结果
         */
        @Builder.Default
        private List<T> res = new ArrayList<>(0);
    }
}
